#include "laurin-network-device.h"
#include <string.h>  //for memset, memcpy


LaurinNetworkDevice::LaurinNetworkDevice(const Glib::ustring& ifaceName): LaurinDevice(ifaceName)
{
	_injection_context = NULL;
	_network = NULL;
	_ip = -1;

	_ready = false;
	if(setDeviceUp() && openCaptureContext() && openInjectionContext())
	{

		u_int32_t mask;
		u_int32_t net;
		char errbuf[PCAP_ERRBUF_SIZE];
		memset(errbuf, 0, PCAP_ERRBUF_SIZE);

		// get mask and network addresses
		if(pcap_lookupnet(_ifaceName.c_str(), &net, & mask, errbuf) < 0)
		{
			_errmess = Glib::ustring("Error on lookup net for ").append(_ifaceName).append(" : ").append(pcap_geterr(_capture_context));
			_ready = false;
		}
		else
		{
			_network = new LaurinIPNetwork(net, mask);
			_ready = true;
		}
	}
}


LaurinNetworkDevice::~LaurinNetworkDevice()
{
	// capture context is closed on the LaurinDevice dtor.

	closeInjectionContext();
}


bool LaurinNetworkDevice::openInjectionContext()
{
	char errbuf[LIBNET_ERRBUF_SIZE];

	if((_injection_context = libnet_init(LIBNET_LINK_ADV, (char*) _ifaceName.c_str(), errbuf)) == NULL)
	{
		_errmess = Glib::ustring("Error on open libnet context for ").append(_ifaceName).append(" : ").append(errbuf);
		return false;
	}

	_ip = libnet_get_ipaddr4(_injection_context);
	return true;
}


void LaurinNetworkDevice::closeInjectionContext()
{
	if(_injection_context != NULL)
			libnet_destroy(_injection_context);
}


u_int32_t LaurinNetworkDevice::getIP() const
{
	return _ip;
}


libnet_t* LaurinNetworkDevice::getInjectionContext() const
{
	return _injection_context;
}


LaurinIPNetwork* LaurinNetworkDevice::getIPNetwork() const
{
	return _network;
}


bool LaurinNetworkDevice::isInitialized() const
{
	return _ready && LaurinDevice::isInitialized();
}


bool LaurinNetworkDevice::setCaptureOptions()
{
	// promisc mode is not important here, disable it.

	if(pcap_set_promisc(_capture_context, 0) < 0)
	{
		_errmess = Glib::ustring("Error on setting capture options for ").append(_ifaceName).append(" : ").append(pcap_geterr(_capture_context));
		return false;
	}

	return LaurinDevice::setCaptureOptions();
}
